<?php

declare(strict_types=1);

namespace core;

class App
{
    public function __construct()
    {
        Session::start();

        // 设置中国时区
        date_default_timezone_set(config('timezone'));

        // 设置调试模式
        if (config('debug')) {
            // 显示错误
            error_reporting(E_ALL);
            ini_set('display_errors', '1');
        } else {
            // 关闭所有错误
            error_reporting(0);
            ini_set('display_errors', '0');
        }

        // 自定义异常
        set_error_handler('\core\App::errorHandler');
        set_exception_handler('\core\App::exceptionHandler');

        // 解析路由
        $this->route();

        // 开启调试追踪
        if (config('trace')) {
            // 用于运行追踪
            $GLOBALS['traceSql'] = [];
            include 'templates/trace.php';
        }
    }

    /**
     * 错误处理程序
     * 通过抛出 ErrorException 将所有错误转换为异常。
     *
     * @param int    $level    错误级别
     * @param string $message  错误消息
     * @param string $file     引发错误的文件名
     * @param int    $line     引发错误所在行
     *
     * @return void
     */
    public static function errorHandler($level, $message, $file = '', $line): void
    {
        if (error_reporting() !== 0) {
            throw new \ErrorException($message, 0, $level, $file, $line);
        }
    }

    /**
     * 异常处理
     *
     * @param Exception $exception  异常
     *
     * @return void
     */
    public static function exceptionHandler($exception)
    {
        // Code is 404 (not found) or 500 (general error)
        $code = $exception->getCode();
        if ($code != 404) {
            $code = 500;
        }
        http_response_code($code);

        if (config('debug')) {
            echo "<h1>错误</h1>";
            echo "<h2>{$exception->getMessage()}</h2>";
            echo "<p> {$exception->getFile()} 第 {$exception->getLine()} 行</p>";
        } else {
            $log = new Log();
            $log->debug(
                $exception->getMessage() . '\n' .
                    $exception->getFile()    . '\n' .
                    $exception->getLine()
            );
            view("errors/{$code}");
        }
    }

    /**
     * 路由解析
     */
    private function route()
    {
        $router = $this->router();
        $controllerName = $router[0];
        // 控制器命名只支持 字母 + 数字
        $mode = '/^([a-z]|[A-Z]|[0-9])+$/Uis';
        $res  = preg_match($mode, $controllerName);
        if (!$res) {
            $controllerName = 'Home';
        }
        $controllerFile = APP_PATH . 'controllers/' . $controllerName . '.php';
        if (!is_file($controllerFile)) {
            $controllerName = 'Home';
            $controllerFile = APP_PATH . 'controllers/Home.php';
            // 控制器不存在，开启 404 页面
            exit('404 -- 1');
        }

        define('CONTROLLER_NAME', $controllerName);
        $controllerName = "\\app\\controllers\\" . ucfirst($controllerName);
        $controller = new $controllerName;
        $methodName = $router[1];
        $res  = preg_match($mode, $methodName);
        if (!$res) {
            $methodName = 'index';
        }
        $graceMethods = array(
            '__init', 'view', 'dataList', 'getDataById', 'getDefaultVal',
            'skipToIndex', 'getCacher', 'cache', 'clearCache', 'removeCache', 'initVal', 'intVal'
        );
        if (in_array($methodName, $graceMethods)) {
            $methodName  = 'index';
        }
        if (!method_exists($controller, $methodName)) {
            $methodName  = 'index';
            //如果对应方法名不存在，启动404页面
            exit('404 -- 2');
        }
        define('METHOD_NAME', $methodName);
        // define('PG_SROOT', str_replace(PG_INDEX_FILE_NAME, '', $_SERVER['PHP_SELF']));
        array_shift($router);
        array_shift($router);
        $controller->gets = $router;
        define('PG_URL', implode('/', $router));
        call_user_func(array($controller, '__init'));
        call_user_func([$controller, $methodName]);
    }

    /**
     * 获取并拆分 URL
     */
    private function router()
    {
        if (isset($_GET['url'])) {
            $url = trim($_GET['url'], '/');
            $url = filter_var($url, FILTER_SANITIZE_URL);
            unset($_GET['url']);
        } else {
            $url = 'home/index';
        }

        $router = explode('/', $url);

        if (empty($router[0])) {
            array_shift($router);
        }
        // if (config('route')) {
        //     $routerArray = require(APP_PATH . '/routes.php');
        //     if (array_key_exists($router[0], $routerArray)) {
        //         $newRouter    = [];
        //         $newRouter[0] = $routerArray[$router[0]][0];
        //         $newRouter[1] = $routerArray[$router[0]][1];
        //         if (!empty($routerArray[$router[0]][2]) && is_array($routerArray[$router[0]][2])) {
        //             $newRouter = array_merge($newRouter, $routerArray[$router[0]][2]);
        //         }
        //         define("PAGE_PAGE",  1);
        //         return $newRouter;
        //     };
        // }
        $router[0] = isset($router[0]) ?  $router[0] : 'home';
        $router[1] = isset($router[1]) ?  $router[1] : 'index';
        for ($i = 2; $i < count($router); $i++) {
            if (preg_match('/^page_(.*)()*$/Ui', $router[$i], $matches)) {
                define("PAGE_NUMBER",  intval($matches[1]));
                array_splice($router, $i, 1);
            }
        }
        if (!defined("PAGE_NUMBER")) {
            define("PAGE_NUMBER",  1);
        }
        return $router;
    }
}
